<script setup>
import { ref, onMounted, watch } from 'vue';
import * as d3 from 'd3';
import sourceToRoot from '@/components/sourceToRoot.vue';
import axios from 'axios';

const treeData = ref([]);
const selectedNodeError = ref(null);
const kpiTreeVisualizer = ref(null);
const openDialog = ref(false);
const ids = ref(['sp-1'])
// 是否连接成功 false为已成功，true为未成功
const loading = ref(0)
const loadingFire = ref(true)

// const data = ref(null)

watch(
    treeData,
    (newList) => {
        renderTree(newList);
    },
    { deep: true, immediate: false }
)

function handleNodeClick(errorData) {
  selectedNodeError.value = errorData.subPoints?.filter(n => n.error === true) || [];
  ids.value = selectedNodeError.value.map(n => n.id)
  console.log("Selected node:", selectedNodeError.value);
  console.log("所有错误",ids.value);
  if (ids.value.length === 0) {
        return;
    }
    openDialog.value = true
}
// 渲染函数
let visualizer = null
function renderTree(list) {
    // 构造D3需要的嵌套工具
    const root = list.find(n => !n.parentId);
    if(!root) return;
    function build(node) {
        return {
            ...node,
            status: node.subPoints?.some(sp => sp.error) ? 'critical' : 'normal',
            children: list
                .filter(n => n.parentId === node.id)
                .map(build)
        };
    }
    const treeData = build(root);

    // 如果是第一次则new一个示例之后直接调用init
    if (!visualizer) {
        const svgElement = document.getElementById('tree-svg');
        visualizer = new KPITreeVisualizer(svgElement, handleNodeClick);
    }
    visualizer.treeData = treeData; // 加入新数据
    visualizer.root = d3.hierarchy(treeData);
    visualizer.root.x0 = visualizer.height / 2;
    visualizer.root.y0 = 0;
    visualizer.update(visualizer.root)
}
class KPITreeVisualizer {
  constructor(svgElement, onClickCallback) {
    this.svg = d3.select(svgElement);
    this.onNodeClick = onClickCallback;
    this.width = svgElement.clientWidth;
    this.height = svgElement.clientHeight;
    this.duration = 750;
    this.treeData = { id: "root", name: "系统根节点", children: [] };
    
    this.init();
  }
  
  init() {
    // 清空并设置SVG
    this.svg.selectAll("*").remove();
    
    // 创建缩放容器
    this.g = this.svg.append("g");
    
    // 设置缩放行为
    this.zoom = d3.zoom()
      .scaleExtent([0.1, 5])
      .on("zoom", (event) => {
        this.g.attr("transform", event.transform);
      });
    
    this.svg.call(this.zoom);
    
    // 创建树布局
    this.tree = d3.tree()
      .size([this.height, this.width - 200]);
    
    // 初始化树
    // this.root = d3.hierarchy(this.treeData);
    // this.root.x0 = this.height / 2;
    // this.root.y0 = 0;
    // this.update(this.root);
  }
  
  update(source) {
    // 计算新树布局
    this.tree(this.root);
    
    // 获取节点和连接
    const nodes = this.root.descendants();
    const links = this.root.links();
    
    // 设置节点位置
    nodes.forEach(d => {
      d.y = d.depth * 300;
    });
    
    // 更新连接线
    const link = this.g.selectAll(".link")
      .data(links, d => d.target.id);
    
    // 添加新连接线
    const linkEnter = link.enter().append("path")
      .attr("class", "link")
      .attr("d", d3.linkHorizontal()
        .x(d => d.y)
        .y(d => d.x))
      .attr("fill", "none")
      .attr("stroke", "#555")
      .attr("stroke-width", 2);
    
    // 更新现有连接线
    link.merge(linkEnter)
      .transition()
      .duration(this.duration)
      .attr("d", d3.linkHorizontal()
        .x(d => d.y)
        .y(d => d.x));
    
    // 移除多余连接线
    link.exit().remove();
    
    // 更新节点
    const node = this.g.selectAll(".node")
      .data(nodes, d => d.id);
    
    // 添加新节点
    const nodeEnter = node.enter().append("g")
      .attr("class", "node")
      // eslint-disable-next-line no-unused-vars
      .attr("transform", d => `translate(${source.y0},${source.x0})`)
      .on("click", (event, d) => this.nodeClicked(d));
    
    // 添加节点圆形
    nodeEnter.append("circle")
      .attr("r", 0)
      .attr("fill", d => this.getNodeColor(d))
      .attr("stroke", "#fff")
      .attr("stroke-width", 2.5);
    
    const st = node.data?.status;
    if (st === 'critical') {
      nodeEnter.append("text")
      .attr("dy", "0.31em")
      .attr("x", d => d.children ? -15 : 15)
      .attr("text-anchor", d => d.children ? "end" : "start")
      .text(d => d.data.name)
      .attr("fill", "#c62828")
      .attr("font-size", "30px");
    }else {
        // 添加节点文本
      nodeEnter.append("text")
      .attr("dy", "0.31em")
      .attr("x", d => d.children ? -20 : 20)
      .attr("text-anchor", d => d.children ? "end" : "start")
      .text(d => d.data.name)
      .attr("fill", "#000")
      .attr("font-size", "30px");
    }
    
    
    // 更新节点位置
    const nodeUpdate = node.merge(nodeEnter)
      .transition()
      .duration(this.duration)
      .attr("transform", d => `translate(${d.y},${d.x})`);
    
    // 更新节点样式
    nodeUpdate.select("circle")
      .attr("r", 20)
      .attr("fill", d => this.getNodeColor(d));
    
    // 移除多余节点
    node.exit()
      .transition()
      .duration(this.duration)
      // eslint-disable-next-line no-unused-vars
      .attr("transform", d => `translate(${source.y},${source.x})`)
      .remove();
    
    // 存储旧位置
    nodes.forEach(d => {
      d.x0 = d.x;
      d.y0 = d.y;
    });
  }
  
  addNode(newNodeData) {
    // 查找父节点
    let parentD3 = this.findD3NodeById(newNodeData.parentId);
    if (!parentD3) parentD3 = this.root;
    
    // 创建新节点
    const newD3Node = d3.hierarchy({
      id: newNodeData.id,
      name: newNodeData.name,
      children: [],
      status: this.determineNodeStatus(newNodeData),
      data: newNodeData
    });
    
    // 添加到父节点
    if (!parentD3.children) parentD3.children = [];
    parentD3.children.push(newD3Node);
    newD3Node.depth = parentD3.depth + 1;
    newD3Node.parent = parentD3;
    
    // 更新树
    // this.root = d3.hierarchy(this.treeData);
    this.update(parentD3);
  }
  
  findD3NodeById(id, node = this.root) {
    if (node.data.id === id) return node;
    if (node.children) {
        for (const child of node.children) {
            const found = this.findD3NodeById(id, child);
            if (found) return found;
        }
    }
    return null;
  }

  findNodeById(id, node = this.treeData) {
    if (node.id === id) return node;
    if (node.children) {
      for (const child of node.children) {
        const found = this.findNodeById(id, child);
        if (found) return found;
      }
    }
    return null;
  }
  
  determineNodeStatus(nodeData) {
    if (nodeData.subPoints) {
      return nodeData.subPoints.some(sp => sp.error) 
        ? 'critical' 
        : 'normal';
    }
    return 'normal';
  }
  
  getNodeColor(node) {
    if (node.data?.status === 'critical') return 'red'
    return 'rgb(0,81,255)';
  }
  
  nodeClicked(d) {
    const nodeRaw = d.data
    if (this.onNodeClick) {
      this.onNodeClick?.(nodeRaw);
    }
    
  }
}
const fetchKPITree = async() => {
  try {
    console.log('发送请求ing');
    
    const response = await axios.get('http://192.168.31.169:5000/kpi', {
      timeout: 60000 // 设置超时时间为 5000 毫秒
    });
    console.log('发送请求结束');
    
    if (!response.data) {
      loading.value = 0
    }
    treeData.value = response.data
    console.log('数据',treeData.value);
    
  }catch (err) {
    if (err.code === 'ECONNABORTED') {
      console.error('请求超时，请检查网络连接或后端服务');
    } else if (err.response && err.response.status === 404) {
      console.error('请求的资源未找到，请检查 URL 是否正确');
    } else {
      console.error('出现错误了', err);
    }
    if (err.response) {
      // 请求已发送，服务器响应状态码非 2xx
      console.error('服务器错误:', err.response.status, err.response.data);
    } else if (err.request) {
      // 请求已发送但无响应
      console.error('无响应:', err.request);
    } else {
      // 其他错误
      console.error('请求错误:', err.message);
    }
  }finally {
    console.log('已发送请求');
  }
}
// 获取火焰图
const fetchFlameGraph = async () => {
  try {
    // 直接请求后端图片接口
    const response = await axios.get('http://192.168.31.56:9000/images/name/test.JPG', {
      responseType: 'blob',
      timeout: 120000
    });
    
    // 创建对象URL
    const url = URL.createObjectURL(response.data);
    
    // 在页面上显示图片
    document.getElementById('flame-graph-img').src = url;
    loadingFire.value = false
    console.log('abc');
    console.log(response.data);
    
    
  } catch (error) {
    console.error('Error loading flame graph:', error);
  }
}
const loadingFireBtn = () => {
  loadingFire.value = true
  fetchFlameGraph()
}
watch(treeData,() => {
  loading.value = 1
})
onMounted(() => {  
  console.log(2222);
  
  // 初始化树可视化
  const svgElement = document.getElementById('tree-svg');
  kpiTreeVisualizer.value = new KPITreeVisualizer(svgElement, handleNodeClick);
  // 开始模拟数据
  // simulateBackend();
    fetchKPITree();
    fetchFlameGraph();
    console.log(3333);
});

</script>

<template>
<div class="kpitree-content">
  <h1>KPI树</h1>
  <div class="tree-container1">
    <svg id="tree-svg" width="98%" height="600" class="tree-body"></svg>
    <el-dialog
        v-model="openDialog"
        title="拓扑图错误链展示 "
        width="800"
        height="600"
        align-center
    >
    <div class="sourcetoroot">
        <source-to-root :ids="ids">
        </source-to-root>
    </div>
    </el-dialog>
    <div class="tree-container-con" v-show="loading === 0">
    <div class="container">
      <div class="tree">
        <div class="branch" style="--x:0">
          <span style="--i:0;"></span>
          <span style="--i:1;"></span>
          <span style="--i:2;"></span>
          <span style="--i:3;"></span>
        </div>
        <div class="branch" style="--x:1">
          <span style="--i:0;"></span>
          <span style="--i:1;"></span>
          <span style="--i:2;"></span>
          <span style="--i:3;"></span>
        </div>
        <div class="branch" style="--x:2">
          <span style="--i:0;"></span>
          <span style="--i:1;"></span>
          <span style="--i:2;"></span>
          <span style="--i:3;"></span>
        </div>
        <div class="branch" style="--x:3">
          <span style="--i:0;"></span>
          <span style="--i:1;"></span>
          <span style="--i:2;"></span>
          <span style="--i:3;"></span>
        </div>
        <div class="stem">
          <span style="--i:0;"></span>
          <span style="--i:1;"></span>
          <span style="--i:2;"></span>
          <span style="--i:3;"></span>
        </div>
        <span class="shadow"></span>
      </div>
    </div>
    <h1>正在加载...</h1>
  </div>
  </div>
  
  <div class="fire-chart">
    <h3>火焰图</h3>
    <el-button v-if="!loadingFire" @click="loadingFireBtn" type="primary" class="loadingFireB">重新加载火焰图</el-button>
    <el-button v-else loading type="primary" class="loadingFireB">加载中...</el-button>
    <img id="flame-graph-img" alt="动态火焰图" v-show="!loadingFire">
    <div class="example-loading" v-show="loadingFire">
      <a-spin />
      <h2>图片加载中...</h2>
    </div>
  </div>
</div>
</template>

<style>
.kpitree-content {
  width: 100%;
  font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}

.kpitree-content h1 {
  font-size: 36px;
  color: rgb(0,81,255);
  margin-bottom: 20px;
  font-weight: 750;
}

.tree-container1 {
  height: 85vh;
  display: flex;
  padding: 20px;
  background: #f8f9fa;
  border-radius: 8px;
  box-shadow: 0 4px 12px rgba(0,0,0,0.1);
  margin: 0 auto;
  position: relative;
}
.tree-container-con {
  position: absolute;
  top: 0;
  left: 0;
  height: 85vh;
  display: flex;
  padding: 20px;
  background: #f8f9fa;
  border-radius: 8px;
  box-shadow: 0 4px 12px rgba(0,0,0,0.1);
  margin: 0 auto;
}
.tree-container-con h1 {
  font-size: 60px;
  display: flex;
  justify-content: center;
  align-items: center;
  color: #69c069;
}

.node circle {
  cursor: pointer;
  transition: fill 0.3s ease;
}
.node circle:hover {
    box-shadow: 0 0 6px rgba(0,0,0,0.1);
    transform: box-shadow 0.3s ease;
}

.node text {
  font-size: 14px;
  font-weight: 600;
}
.tree-body {
    margin: 0 auto;
}
.link {
  fill: none;
  stroke: #c0c0c0;
  stroke-width: 1.5px;
  transition: stroke 0.3s ease;
}

.error-panel {
  margin-left: 30px;
  padding: 20px;
  background: white;
  border-radius: 8px;
  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
  min-width: 300px;
}

.error-point {
  padding: 8px 12px;
  margin: 8px 0;
  background: #f1f1f1;
  border-radius: 4px;
}

.error-critical {
  background: #ffebee;
  color: #c62828;
  font-weight: bold;
  border-left: 3px solid #c62828;
}
.sourcetoroot {
    height: 700px;
    margin: 0 auto;
    width: 800px;
}
.fire-chart {
  margin-top: 30px;
  position: relative;
}
.fire-chart h3 {
  font-size: 30px;
  color: rgb(0,81,255);
  margin-bottom: 10px;
  font-weight: 750;
}
.fire-chart img {
  width: 100%;
  height: 100%;
  height: calc(100% - 40px);
}
.fire-chart .loadingFireB {
  position: absolute;
  right: 20px;
  top: 0;
}
.fire-chart .example-loading {
  text-align: center;
  background: rgba(0, 0, 0, 0.05);
  border-radius: 4px;
  margin-bottom: 20px;
  padding: 30px 40px 20px;
  margin: 20px 0;
}
.example-loading h2 {
  font-size: 20px;
  margin-top: 20px;
  color: rgb(0,81,255);
}
 .container {
    width: 50%;
    display: flex;
    justify-content: center;
    align-items: center;
  }

  .tree {
    position: relative;
    width: 100px; /* 放大到原来的两倍 */
    height: 100px; /* 放大到原来的两倍 */
    transform-style: preserve-3d;
    transform: rotateX(-20deg) rotateY(30deg);
    animation: treeAnimate 5s linear infinite;
  }

  @keyframes treeAnimate {
    0% {
      transform: rotateX(-20deg) rotateY(360deg);
    }

    100% {
      transform: rotateX(-20deg) rotateY(0deg);
    }
  }

  .tree div {
    position: absolute;
    top: -100px; /* 放大到原来的两倍 */
    left: 0;
    width: 100%;
    height: 100%;
    transform-style: preserve-3d;
    transform: translateY(calc(50px * var(--x))); /* 放大到原来的两倍 */
  }

  .tree div.branch span {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: linear-gradient(90deg, #69c069, #77dd77);
    clip-path: polygon(50% 0%, 0% 100%, 100% 100%);
    border-bottom: 10px solid #00000019; /* 放大到原来的两倍 */
    transform-origin: bottom;
    transform: rotateY(calc(90deg * var(--i))) rotateX(30deg) translateZ(57px); /* 放大到原来的两倍 */
  }

  .tree div.stem span {
    position: absolute;
    top: 220px; /* 放大到原来的两倍 */
    left: calc(50% - 15px); /* 放大到原来的两倍 */
    width: 30px; /* 放大到原来的两倍 */
    height: 50%;
    background: linear-gradient(90deg, #bb4622, #df7214);
    border-bottom: 10px solid #00000019; /* 放大到原来的两倍 */
    transform-origin: bottom;
    transform: rotateY(calc(90deg * var(--i))) translateZ(15px); /* 放大到原来的两倍 */
  }

  .shadow {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: rgba(0, 0, 0, 0.4);
    filter: blur(40px); /* 放大到原来的两倍 */
    transform-style: preserve-3d;
    transform: rotateX(90deg) translateZ(-130px); /* 放大到原来的两倍 */
  }

</style>